const fs = require('fs-extra');
const path = require('path');
const XLSX = require('xlsx');
const axios = require('axios');
const { v4: uuidv4 } = require('uuid');
const Promise = require('bluebird');

// 存储验证状态的内存数据库
const validationStatus = new Map();

// 结果文件存储目录
const RESULTS_DIR = path.join(__dirname, '../results');

/**
 * 开始验证手机号码
 * @param {Array<string>} phoneNumbers - 手机号码数组
 * @param {string} uploadId - 上传ID
 * @param {number} maxConcurrency - 最大并发数
 */
exports.startValidation = async (phoneNumbers, uploadId, maxConcurrency) => {
  // 初始化验证状态
  validationStatus.set(uploadId, {
    status: 'processing',
    progress: 0,
    resultUrls: { valid: null, invalid: null, failed: null },
    message: '开始验证手机号码',
    startTime: new Date()
  });
  
  try {
    // 每批500个号码，符合接口A的要求
    const batchSize = 500;
    const batches = [];
    
    // 分割号码数组为批次
    for (let i = 0; i < phoneNumbers.length; i += batchSize) {
      batches.push(phoneNumbers.slice(i, i + batchSize));
    }
    
    const totalBatches = batches.length;
    const concurrencyBatchSize = Math.min(maxConcurrency, totalBatches);
    
    // 创建TXT分流写入器（按需创建，避免生成空文件）
    const { getPaths, writeBatch, finalize } = await createResultsTxtWriters(uploadId);
    
    // 分块处理批次，控制并发
    for (let i = 0; i < totalBatches; i += concurrencyBatchSize) {
      const batchChunk = batches.slice(i, i + concurrencyBatchSize);
      
      // 并发处理当前块中的所有批次
      await Promise.all(
        batchChunk.map((batch, index) => 
          validateBatch(batch)
            .then(async (batchResults) => {
              // 将结果写入CSV（流式，避免占用内存）
              await writeBatch(batchResults);
              
              // 更新进度
              const completed = i + index + 1;
              const progress = Math.floor((completed / totalBatches) * 100);
              
              validationStatus.set(uploadId, {
                ...validationStatus.get(uploadId),
                progress,
                message: `已完成 ${completed}/${totalBatches} 批次验证`
              });
            })
        )
      );
    }
    
    // 完成写入
    await finalize();

    const { validPath, invalidPath, failedPath } = getPaths();
    
    // 更新状态为完成
    validationStatus.set(uploadId, {
      status: 'completed',
      progress: 100,
      resultUrls: {
        valid: validPath || null,
        invalid: invalidPath || null,
        failed: failedPath || null
      },
      message: '验证完成',
      startTime: validationStatus.get(uploadId).startTime,
      endTime: new Date()
    });
    
    return { validPath, invalidPath, failedPath };
  } catch (error) {
    console.error(`验证过程出错: ${error.message}`);
    
    // 更新状态为失败
    validationStatus.set(uploadId, {
      ...validationStatus.get(uploadId),
      status: 'failed',
      message: `验证失败: ${error.message}`,
      endTime: new Date()
    });
    
    throw error;
  }
};

/**
 * 获取验证状态
 * @param {string} uploadId - 上传ID
 * @returns {Object|null} 验证状态
 */
exports.getValidationStatus = async (uploadId) => {
  return validationStatus.get(uploadId) || null;
};

/**
 * 获取验证结果
 * @param {string} uploadId - 上传ID
 * @returns {Promise<Array<Object>|null>} 验证结果
 */
exports.getValidationResult = async (uploadId) => {
  const status = validationStatus.get(uploadId);
  
  if (!status || status.status !== 'completed' || !status.resultUrl) {
    return null;
  }
  
  try {
    const ext = path.extname(status.resultUrl).toLowerCase();
    if (ext === '.xlsx') {
      const workbook = XLSX.readFile(status.resultUrl);
      const worksheet = workbook.Sheets[workbook.SheetNames[0]];
      return XLSX.utils.sheet_to_json(worksheet);
    } else if (ext === '.csv') {
      // 流式读取CSV结果
      const csv = require('csv-parser');
      return await new Promise((resolve, reject) => {
        const results = [];
        fs.createReadStream(status.resultUrl)
          .pipe(csv())
          .on('data', (data) => results.push(data))
          .on('end', () => resolve(results))
          .on('error', reject);
      });
    } else {
      throw new Error(`不支持的结果文件格式: ${ext}`);
    }
  } catch (error) {
    console.error(`读取结果文件出错: ${error.message}`);
    return null;
  }
};

/**
 * 验证一批手机号码
 * @param {Array<string>} phones - 手机号码数组（最多500个）
 * @returns {Promise<Array<Object>>} 验证结果
 */
const validateBatch = async (phones) => {
  if (!phones || phones.length === 0) {
    return [];
  }
  
  try {
    // 调用接口A
    const response = await axios.post(
      process.env.API_URL,
      { phones },
      {
        timeout: 10000, // 10秒超时
        headers: {
          'Content-Type': 'application/json',
          // 可以添加其他必要的头信息
        }
      }
    );
    
    // 检查响应状态
    if (response.data.status !== 200) {
      // 接口返回非200状态，整批标记为验证失败
      return phones.map(phone => ({
        phone,
        status: 'validation_failed',
        message: `API返回状态码: ${response.data.status}`
      }));
    }
    
    // 处理每个号码的结果
    return phones.map(phone => {
      if (response.data.data && response.data.data[phone]) {
        return {
          phone,
          status: 'valid',
          message: '验证成功'
        };
      } else {
        return {
          phone,
          status: 'invalid',
          message: '验证不通过'
        };
      }
    });
  } catch (error) {
    console.error(`验证批次出错: ${error.message}`);
    
    // 发生错误，整批标记为错误
    return phones.map(phone => ({
      phone,
      status: 'error',
      message: error.message || '验证过程发生错误'
    }));
  }
};

/**
 * 生成结果文件
 * @param {Array<Object>} results - 验证结果
 * @param {string} uploadId - 上传ID
 * @returns {Promise<string>} 结果文件路径
 */
const generateResultsFile = async (results, uploadId) => {
  // 准备Excel数据
  const worksheetData = results.map(result => ({
    '手机号码': result.phone,
    '状态': 
      result.status === 'valid' ? '验证成功' : 
      result.status === 'invalid' ? '验证不通过' : 
      result.status === 'validation_failed' ? '验证失败' : '错误',
    '消息': result.message
  }));
  
  // 创建工作簿和工作表
  const worksheet = XLSX.utils.json_to_sheet(worksheetData);
  const workbook = XLSX.utils.book_new();
  XLSX.utils.book_append_sheet(workbook, worksheet, '验证结果');
  
  // 确保结果目录存在
  await fs.ensureDir(RESULTS_DIR);
  
  // 生成文件名和路径
  const filename = `${uploadId}-results.xlsx`;
  const filePath = path.join(RESULTS_DIR, filename);
  
  // 写入文件
  await XLSX.writeFile(workbook, filePath);
  return filePath;
};

/**
 * 创建三个TXT文件的流式写入器
 * valid.txt: 仅手机号码（验证通过）
 * invalid.txt: 仅手机号码（验证不通过）
 * failed.txt: 手机号,失败原因（接口失败/异常等）
 */
const createResultsTxtWriters = async (uploadId) => {
  await fs.ensureDir(RESULTS_DIR);

  let validPath = null;
  let invalidPath = null;
  let failedPath = null;

  let validStream = null;
  let invalidStream = null;
  let failedStream = null;

  // 序列化所有写入，避免并发写导致积累 drain 监听器
  let writeChain = Promise.resolve();
  const queue = (task) => (writeChain = writeChain.then(task).catch(() => {}));

  const ensureStream = (type) => {
    if (type === 'valid' && !validStream) {
      validPath = path.join(RESULTS_DIR, `${uploadId}-valid.txt`);
      validStream = fs.createWriteStream(validPath, { encoding: 'utf8' });
    } else if (type === 'invalid' && !invalidStream) {
      invalidPath = path.join(RESULTS_DIR, `${uploadId}-invalid.txt`);
      invalidStream = fs.createWriteStream(invalidPath, { encoding: 'utf8' });
    } else if (type === 'failed' && !failedStream) {
      failedPath = path.join(RESULTS_DIR, `${uploadId}-failed.txt`);
      failedStream = fs.createWriteStream(failedPath, { encoding: 'utf8' });
    }
  };

  const writeToStream = async (stream, chunk) => {
    if (!chunk) return;
    if (!stream.write(chunk)) {
      await new Promise((resolve) => stream.once('drain', resolve));
    }
  };

  const escapeText = (value) => {
    if (value == null) return '';
    return String(value).replace(/[\r\n]/g, ' ');
  };

  const writeBatch = async (rows) => {
    if (!rows || rows.length === 0) return;
    let validChunk = '';
    let invalidChunk = '';
    let failedChunk = '';

    for (const r of rows) {
      if (r.status === 'valid') {
        validChunk += `${r.phone}\n`;
      } else if (r.status === 'invalid') {
        invalidChunk += `${r.phone}\n`;
      } else if (r.status === 'validation_failed' || r.status === 'error') {
        failedChunk += `${r.phone},${escapeText(r.message)}\n`;
      } else {
        failedChunk += `${r.phone},${escapeText(r.message)}\n`;
      }
    }

    // 入队，保证顺序写，避免并发 drain 监听
    await queue(async () => {
      if (validChunk) {
        ensureStream('valid');
        await writeToStream(validStream, validChunk);
      }
      if (invalidChunk) {
        ensureStream('invalid');
        await writeToStream(invalidStream, invalidChunk);
      }
      if (failedChunk) {
        ensureStream('failed');
        await writeToStream(failedStream, failedChunk);
      }
    });
  };

  const finalize = async () => {
    const tasks = [];
    if (validStream) {
      tasks.push(new Promise((resolve, reject) => validStream.end((err) => err ? reject(err) : resolve())));
    }
    if (invalidStream) {
      tasks.push(new Promise((resolve, reject) => invalidStream.end((err) => err ? reject(err) : resolve())));
    }
    if (failedStream) {
      tasks.push(new Promise((resolve, reject) => failedStream.end((err) => err ? reject(err) : resolve())));
    }
    await Promise.all(tasks);
  };

  const getPaths = () => ({ validPath, invalidPath, failedPath });

  return { getPaths, writeBatch, finalize };
};
